/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 * $Id: EmergencyStopServer.hpp,v 1.8 2009-12-08 10:48:28 morsko Exp $
 *
 * \file
 * \brief MaCI - Emergency Stop Server interface
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 */
#ifndef _MACI_INTERFACE_EMERGENCYSTOPSERVER_HPP_
#define _MACI_INTERFACE_EMERGENCYSTOPSERVER_HPP_
#include "MaCI.hpp"
#include "EmergencyStopData.hpp"
#include "thread.hpp"
#include "sync.hpp"
#include <map>

// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
  class GIMIMessage;
}

namespace MaCI {
  namespace EmergencyStop {

    /** MaCI - EmergencyStop Server interface
     * 
     * This class contains the methods and types for providing
     * the EmergencyStop service in the GIMnet.
     */
    class CEmergencyStopServer : public MaCI::CMaCI, 
                                 private gim::CSync,
                                 private gim::CThread
    {
    public:
      /** Constructor.
       * 
       * Constructor of the EmergencyStopServer. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aMaCICtrlServerPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       * used to indicate the instance of devices of same type.
       * @param[in] aDescription User provided description about
       * service. This description will be appended after text
       * 'MaCI-EmergencyStopServer; ' in the GIMI service description
       * field.
       */
      CEmergencyStopServer(MaCICtrl::CMaCICtrlServer *aMaCICtrlServerPtr, 
                      const int aInterfaceMinor,
                      const std::string &aDescription = "");


      /** Destructor.
       */
      ~CEmergencyStopServer();
 

      /** Open device.
       *
       * Opens the device, basicly registers device to GIMI.
       *  
       * @return                Returns a value of type EMaCIError. 
       *                        
       * \see EMaCIError
       */
      MaCI::EMaCIError DoOpen(void);


      /** Close device.
       *
       * Closes the device. Closes all GIMI registrations and queues.
       *
       * @return                Returns a value of type EMaCIError.
       *
       * \see EMaCIError
       */
      MaCI::EMaCIError DoClose(void);
      


      /** Send a EmergencyStop interface event. 
       * 
       * All fields present in the provided container will be transmitted.
       * The Event must atleast contain some position. (Empty events
       * will not be sent)
       *
       * \see CEmergencyStopData
       *
       * @param[in] aData       Reference to CEmergencyStopData element containing
       *                        atleast the position.
       * @return                'true' when the element was OK and was 
       *                        succesfully sent to GIMnet. (No guarantees
       *                        are made about reaching any subscriber).
       *                        'false' when the container was broken,
       *                        didn't contain correct elements or there
       *                        was some problem at the GIMnet layer.
       */
      bool SendEmergencyStopEvent(const CEmergencyStopData &aData);

      /** Wait for command from Client.
       *
       * This function waits for a Command to arrive from client, and returns it
       * in the provided reference to CEmergencyStopData.
       * The function guarantees that the data element contains a TCommand,
       * but the user must check whether all accompanying elements required for
       * the specified command exist.
       * 
       * KCommandActivateEmergencyStop and KCommandDeactivateEmergencyStop, 
       * will be the only messages arriving from this function. Please reply 
       * these messages when activating and deactivating emergency stop, 
       * because this interface is used in cricatal situations. That's why the
       * client side must know if the message have actually arrived.
       *
       * @param[out] aData      Reference to CEmergencyStopData to be filled.
       * @param[in] aSource     Reference to message source information.
       * @param[in] aTimeout_ms Time to wait for a command (milliseconds).
       * @param[in] aSkipQueued If this value is set to 'true', the
       *                        function will only return the last
       *                        received command and pop older ones
       *                        out from the queue. If this is set to
       *                        'false', all commands are received in
       *                        order. If parameter is undefined, 
       *                        default is 'false'.
       * @return                'KMaCIOK'  when succesfully received
       *                        a new command. KMaCITimeout when operation
       *                        timed out before a command was received.
       *                        Other errors returned when appropriate.
       *                        (See the MaCI::EMaCIError for description)
       */
      EMaCIError WaitCommand(CEmergencyStopData &aData, 
                             SMessageSource &aSource,
                             const unsigned int aTimeout_ms,
                             bool aSkipQueued);

      /** Sets timeout for client watchdog, and client drop time.
       *
       * @param aTimeout_ms         Time when emergency stop message created if no watchdog
       *                            message arrived from client
       * @param aClientDropTime     Time after client is dropped from active client list if no 
       *                            watchdog message arrived from client
       */
     void SetTimeoutTime(unsigned int aTimeout_ms,
                          MaCI::Common::TTimestamp aClientDropTime);


      /** Sends reply message to client
       *
       * @param[in] aData       Reference to CEmergencyStopData. This data will be sent to
       *                        client for reply
       * @param[in] aSource     Reference to messageSource. Get this messageSource from
       *                        WaitCommand.
       * @return                'KMaCIOK' when reply message succesfully sent.
       *                        Other errors returned when appropriate.
       *                        (See the MaCI::EMaCIError for description)
       * \see EMaCIError
       */
      MaCI::EMaCIError SendReply(const CEmergencyStopData &aData,
                                 const SMessageSource &aSource);
    private:

      int ThreadFunction(const int aThreadNumber); ///< Thread function, calls the other function depending on
                                                   ///  thread number
      int ProcessMessage(const gimi::GIMIMessage &msg); ///< Incoming data processor function
      int ClientMonitoringThread();                ///< Thread for monitoring active clients
      int IncomingMessageHandlerThread();          ///< Thread for handling incoming messages.
      //      MaCI::EMaCIError SendReply(const CParameterData &aData,const SMessageSource &aSource);
      // Variables
      bool iServerActive; ///< Is the server active? - flag
      std::string iServiceDescription; ///< Service description field.
      unsigned int iTimeoutTime_ms;               ///< Time between active client watchdog messages.
      MaCI::Common::TTimestamp iClientDropTime;   ///< Time to wait before inactive client will be dropped from the active client list
      bool iTimeoutTimesSet;                      ///< tells if the timeout values has been set.
      std::list<CEmergencyStopData *> iEmergencyStopArray; ///< Array of unprocessed commands.
      std::list<SMessageSource *> iMessageSourceArray; ///< Array of message sources of unprocessed commands.
      std::map<int,MaCI::Common::TTimestamp> iActiveClients; ///< map of active clients. first =clientId, second =last command timestamp


    };

  }
}


#endif //_MACI_INTERFACE_POSITIONSERVER_HPP_
